from PyQt5.QtCore import QTimer, QThread, pyqtSignal
from PyQt5.QtGui import QImage
from PyQt5.QtCore import QCoreApplication
import traceback
from threading import Lock #在设置参数和读取帧时，使用线程锁确保同一时间只有一个线程访问摄像头
import sys
import cv2
import time
from pathlib import Path
from HslCommunication import MelsecMcNet, ModbusTcpNet  

def excepthook(exc_type, exc_value, exc_tb):
    traceback.print_exception(exc_type, exc_value, exc_tb)
    sys.exit(1)

sys.excepthook = excepthook  # 重写异常钩子




class PlcThread(QThread):
    jig_flip = pyqtSignal()  # 自定义信号，用于传递图像
    device_value_changed = pyqtSignal(str, int)  # 信号传递软元件地址和值

    def __init__(self, Ip,Port):
        super().__init__()
        self.Ip = Ip
        self.Port = Port
        self.running = False
        self.lock = Lock()  # 创建线程锁
        self.monitored_devices = {}  # 监控设备字典 {地址: {频率, 最后检查时间}}
        self.monitored_lock = Lock()  # 监控字典的锁

    def run(self):
        self.melsec = MelsecMcNet(self.Ip, int(self.Port))
        print(f"尝试连接 PLC: {self.Ip}:{self.Port}\n")
        self.running = True
        while self.running:
            current_time = time.time()
            # 复制当前监控列表避免迭代时修改
            with self.monitored_lock:
                monitored = list(self.monitored_devices.items())
            
            for soft_device, info in monitored:
                freq = info['frequency']
                last_check = info['last_check']
                
                if current_time - last_check >= freq:
                    value = self.read(soft_device)
                    if value is not None and value.IsSuccess:
                        self.device_value_changed.emit(soft_device, value.Content)
                    
                    # 更新检查时间
                    with self.monitored_lock:
                        if soft_device in self.monitored_devices:
                            self.monitored_devices[soft_device]['last_check'] = current_time
            time.sleep(0.1)  # 降低CPU占用

    def stop(self):
        self.running = False
        self.wait()
        if hasattr(self, 'melsec'):
            self.melsec.ConnectClose()

    def read(self,soft_device):
        try:
            connect = self.melsec.ConnectServer()
            if connect.IsSuccess:
                with self.lock:
                    value = self.melsec.Read(soft_device)
            else:
                value=None
                print(f"连接失败: {connect.Message}")
        except Exception as e:
            value=None
            print(f"PLC通信异常: {e}")
        return value

    def write(self,soft_device,value):
        try:
            connect = self.melsec.ConnectServer()
            if connect.IsSuccess:
                with self.lock:
                    result = self.melsec.Write(soft_device,value)
            else:
                result=False
                print(f"连接失败: {connect.Message}")
        except Exception as e:
            result=False
            print(f"PLC通信异常: {e}")
        return result

    def monitor_start(self, soft_device, frequency):
        """启动监控指定软元件"""
        if not isinstance(frequency, (int, float)) or frequency <= 0:
            raise ValueError("频率必须为正数")
        with self.monitored_lock:
            self.monitored_devices[soft_device] = {
                'frequency': frequency,
                'last_check': time.time()
            }

    def monitor_stop(self, soft_device):
        """停止监控指定软元件"""
        with self.monitored_lock:
            if soft_device in self.monitored_devices:
                del self.monitored_devices[soft_device]

    def is_monitoring(self, soft_device):
        with self.monitored_lock:
            return soft_device in self.monitored_devices





